package bootstrap

import (
	"com.codingq92/go-chat/app/models"
	g "com.codingq92/go-chat/global"
	"fmt"
	"go.uber.org/zap"
	"gopkg.in/natefinch/lumberjack.v2"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"io"
	"log"
	"os"
	"time"
)

func InitDB() {
	// 根据驱动配置进行初始化
	switch g.Config.Database.Driver {
	case "mysql":
		initMySqlGorm()
	default:
		initMySqlGorm()
	}
}

// 初始化 mysql
func initMySqlGorm() {
	dbConfig := g.Config.Database
	if dbConfig.Database == "" {
		g.Log.Error("database is nil")
		return
	}
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=True&loc=Local",
		dbConfig.UserName, dbConfig.Password, dbConfig.Host, dbConfig.Port, dbConfig.Database, dbConfig.Charset)
	mysqlConfig := mysql.Config{
		DSN:                       dsn,   // DSN data source name
		DefaultStringSize:         191,   // string 类型字段的默认长度
		DisableDatetimePrecision:  true,  // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,  // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false, // 根据版本自动配置
	}
	if db, err := gorm.Open(mysql.New(mysqlConfig), &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: true,            // 禁用自动创建外键约束
		Logger:                                   getGormLogger(), // 使用自定义 Logger
	}); err != nil {
		g.Log.Error("mysql connect failed, err:", zap.Any("err", err))
		return
	} else {
		sqlDB, _ := db.DB()
		sqlDB.SetMaxIdleConns(dbConfig.MaxIdleConn)
		sqlDB.SetMaxOpenConns(dbConfig.MaxOpenConn)
		//数据库表初始化
		initMySqlTables(db)
		g.DB = db
	}
}

func initMySqlTables(db *gorm.DB) {
	err := db.AutoMigrate(
		models.User{},
	)
	if err != nil {
		g.Log.Error("mysql auto migrate failed, err:", zap.Any("err", err))
		os.Exit(0)
	}
}

func getGormLogger() logger.Interface {
	var logMode logger.LogLevel
	switch g.Config.Database.LogMode {
	case "silent":
		logMode = logger.Silent
	case "error":
		logMode = logger.Error
	case "warn":
		logMode = logger.Warn
	case "info":
		logMode = logger.Info
	default:
		logMode = logger.Info
	}
	return logger.New(getGormLogWriter(), logger.Config{
		SlowThreshold:             100 * time.Millisecond,                 // 慢 SQL 阈值
		LogLevel:                  logMode,                                // 日志级别
		IgnoreRecordNotFoundError: false,                                  // 忽略ErrRecordNotFound（记录未找到）错误
		Colorful:                  !g.Config.Database.EnableFileLogWriter, // 禁用彩色打印
	})
}

func getGormLogWriter() logger.Writer {
	var writer io.Writer
	// 是否启用日志文件
	if g.Config.Database.EnableFileLogWriter {
		// 自定义 Writer
		writer = &lumberjack.Logger{
			Filename:   g.Config.Log.RootDir + "/" + g.Config.Database.LogFilename,
			MaxSize:    g.Config.Log.MaxSize,
			MaxBackups: g.Config.Log.MaxBackups,
			MaxAge:     g.Config.Log.MaxAge,
			Compress:   g.Config.Log.Compress,
		}
	} else {
		// 默认 Writer
		writer = os.Stdout
	}
	return log.New(writer, "\r\n", log.LstdFlags)
}
